package com.franklin.ideaplugin.api.utils.psi;

import cn.hutool.core.collection.CollectionUtil;
import com.franklin.ideaplugin.api.constants.PsiConstants;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author Ye Junhui
 * @since 2024/1/2
 */
public class PsiClassUtils implements PsiConstants {

    /**
     * 获取包含的类层级
     *
     * @param psiElement
     * @return
     */
    public static List<PsiClass> getContainingClasses(@NotNull PsiElement psiElement) {
        return PsiTreeUtil.collectParents(
                psiElement,
                PsiClass.class,
                true,
                psiElement1 -> false
        );
    }

    /**
     * 类全称
     * @param psiElement
     * @return
     */
    public static String resolveContainingClassQualifiedName(@NotNull PsiElement psiElement){
        return resolveContainingClassName(psiElement, true);
    }

    /**
     * 类简称
     * @param psiElement
     * @return
     */
    public static String resolveContainingClassSimpleName(@NotNull PsiElement psiElement){
        return resolveContainingClassName(psiElement, false);
    }

    /**
     * 获取方法名
     *
     * @param psiElement
     * @param isQualifiedName
     * @return
     */
    private static String resolveContainingClassName(@NotNull PsiElement psiElement, boolean isQualifiedName) {
        List<PsiClass> containingClasses = getContainingClasses(psiElement);
        if (CollectionUtil.isEmpty(containingClasses)) {
            return "";
        }
        //寻找匿名内部类
        List<String> nameList = Lists.newArrayList();
        for (int i = 0; i < containingClasses.size(); i++) {
            PsiClass psiClass = containingClasses.get(i);
            if (psiClass instanceof PsiAnonymousClass) {
                //匿名内部类
                //父类
                PsiClass parentClass = containingClasses.get(i + 1);
                //子类
                Collection<PsiClass> childClasses = PsiTreeUtil.findChildrenOfAnyType(parentClass, PsiClass.class);
                //转List
                List<PsiClass> childClassList = Lists.newArrayList(childClasses);
                for (int j = 0; j < childClassList.size(); j++) {
                    PsiClass childClass = childClassList.get(j);
                    if (childClass.equals(psiClass)){
                        //目标匿名内部类
                        nameList.add(String.valueOf(j + 1));
                        break;
                    }
                }
            }else {
                //普通类
                String className = psiClass.getName();
                if (i == containingClasses.size() - 1 && isQualifiedName){
                    className = psiClass.getQualifiedName();
                }
                nameList.add(className);
            }
        }
        //翻转
        List<String> reverseNameList = Lists.reverse(nameList);
        //拼装
        return reverseNameList.stream()
                .collect(Collectors.joining("$"));
    }


    public static boolean isNotSupportType(PsiClass psiClass){
        if (Objects.isNull(psiClass)){
            return false;
        }
        return psiClass.isEnum() || psiClass.isInterface();
    }

    /**
     * 查找类
     *
     * @param clazz
     * @return
     */
    public static PsiClass findPsiClass(Project project, Class<?> clazz) {
        return findPsiClass(project,clazz.getName());
    }

    /**
     * 查找类
     *
     * @param classQualifiedName
     * @return
     */
    public static PsiClass findPsiClass(Project project, String classQualifiedName) {
        return JavaPsiFacade.getInstance(project)
                .findClass(classQualifiedName, GlobalSearchScope.allScope(project));
    }

    /**
     * 是否继承
     *
     * @param parent
     * @param child
     * @return
     */
    public static boolean isInheritorOrEquals(PsiClass parent, PsiClass child) {
        if (Objects.isNull(parent) || Objects.isNull(child)) {
            return false;
        }
        return child.isInheritor(parent, true) || parent.equals(child);
    }

    /**
     * 是否是java集合（collection|map）
     *
     * @param psiClass
     * @return
     */
    @SuppressWarnings("UnChecked")
    public static boolean isJavaCollectionClass(PsiClass psiClass){
        return isJavaCollectionClass(psiClass.getProject(),psiClass);
    }

    /**
     * 是否是java集合collection
     *
     * @param project
     * @param psiClass
     * @return
     */
    public static boolean isJavaCollectionClass(Project project, PsiClass psiClass){
        //集合
        PsiClass collectionPsiClass = findPsiClass(project,Collection.class);
        return isInheritorOrEquals(collectionPsiClass, psiClass);
    }

    /**
     * 是否是java集合map
     *
     * @param project
     * @param psiClass
     * @return
     */
    public static boolean isJavaMapClass(Project project, PsiClass psiClass){
        //map
        PsiClass mapPsiClass = findPsiClass(project,Map.class);
        return isInheritorOrEquals(mapPsiClass, psiClass);
    }
}
